home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / pascal / tpfort12.zip / TPFORT.DOC < prev   
Text File  |  1989-11-28  |  16KB  |  352 lines

  1. TPFort v 1.2 - A link from Turbo Pascal to MS Fortran.  
  2.  
  3. Copyright (c) 1989 D.J. Murdoch.  All rights reserved.
  4.  
  5. PURPOSE
  6.  
  7. TPFort is a collection of several procedures that allow Microsoft Fortran 
  8. routines to be called from Turbo Pascal.  I wrote it so that I could use the 
  9. binary-only NAG Fortran library for numerical routines in Turbo Pascal 
  10. programs, but it ended up being a general purpose linker.
  11.  
  12. PRICE
  13.  
  14. TPFort is absolutely free to use and incorporate into your own programs for 
  15. any purpose.  Distribute it to anyone you like, but please don't remove my 
  16. copyright notice or modify it in any other way.  Source code is available 
  17. (see below), but is not necessary to be able to use TPFort with Turbo Pascal 
  18. version 5.5. 
  19.  
  20. METHOD 
  21.  
  22. The Fortran routines are compiled into their own loader file which is loaded at 
  23. run time by a Turbo Pascal program, making most of the Fortran subroutines and 
  24. functions available to the Pascal program.  The molasses-slow Fortran compiler 
  25. and linker need only be run once to create the loader; changes to the Pascal 
  26. part of the program don't force recompiling or re-linking of the Fortran part.
  27.  
  28. INSTRUCTIONS
  29.  
  30. There are several steps involved in preparing a Fortran routines to be called 
  31. from Turbo Pascal.  
  32.  
  33. 1.   Preparing the Fortran Program
  34.  
  35. Write a Fortran program which includes the following declarations and a call 
  36. to CALLTP, in the following format: 
  37.  
  38.         EXTERNAL routine1, routine2, ..., routineX
  39.  
  40.         CALL CALLTP(routine1, routine2, ..., routineX, X)
  41.  
  42. where routine1 through to routineX are the names of the Fortran routines you 
  43. wish to make available to your Turbo Pascal program, and X is an integer value
  44. giving the number of routines being passed.  The external declaration is 
  45. extremely important; if not given, Fortran will assume the routine names are 
  46. local integer or real variables, and things will get really messed up.
  47.  
  48. This loader may do anything else, such as reading data from files, allocating 
  49. space, etc.  It's not all that important where the call to CALLTP takes place, 
  50. but more efficient use will be made of the program stack if the call comes 
  51. somewhere in the main program, rather than in a function or subroutine. 
  52.  
  53. After this call and any other initialization necessary, the program should
  54. exit.  As this will close any open files, and I/O done while TP is active
  55. is probably unreliable, it should complete any I/O operations before quitting, 
  56. and the routines being passed should avoid doing I/O.
  57.  
  58. Compile this routine and link it to the object file CALLTP.OBJ.  Be sure to
  59. specify to the linker that a larger than normal stack will be needed - I'd
  60. suggest a minimum of 16K. The Turbo Pascal program will be using this stack 
  61. instead of its own much of the time, and TP makes much heavier use of the 
  62. stack than does Fortran.
  63.  
  64. Warning:  Don't try running the loader program on its own, unless you avoid 
  65. executing the call to CALLTP.  If TP isn't there to catch that call, you're 
  66. very likely to crash.  It might be a good idea to rename the .EXE with a non-
  67. executable extension such as .LDR just to be sure. 
  68.  
  69. 2.   Preparing the TP dummy procedures
  70.  
  71. You need to create dummy versions of all the Fortran routines that you want to 
  72. call.  They _must_ be declared as "far" routines, either through the use of 
  73. the $F+ compiler directive, or by putting them in the interface section of a 
  74. unit.  I'd suggest isolating all of them into their own unit and interfacing 
  75. them.
  76.  
  77. Each of the dummy routines takes an argument list that corresponds exactly to 
  78. the argument list of the Fortran routine.  By default, all Fortran arguments 
  79. are passed by reference, so these should be too, by declaring them as "var" 
  80. parameters.  The following list gives corresponding types between the two 
  81. languages:
  82.  
  83.   Fortran               TP
  84.  
  85.   INTEGER*2             integer
  86.   INTEGER*4             longint
  87.   INTEGER               longint
  88.   REAL                  single
  89.   REAL*4                single
  90.   REAL*8                double
  91.   DOUBLE PRECISION      double
  92.   CHARACTER*n           array[1..n] of char
  93.   COMPLEX               fort_complex8
  94.   COMPLEX*8             fort_complex8        These types will be declared in
  95.   COMPLEX*16            fort_complex16       the FortLink unit someday
  96.   LOGICAL               fort_logical 
  97.   EXTERNAL              (special - see note below)
  98.  
  99. Note also that Fortran and TP use different conventions for the order of
  100. indices in multi-dimensional arrays.  For example, the Fortran array
  101.  
  102.   REAL X(10,20,30)
  103.  
  104. would be declared as
  105.  
  106.   x : array[1..30,1..20,1..10] of single;
  107.  
  108. in TP. Note also that TP (up to version 5.5, at least) has no facility for 
  109. variable dimensions on arrays:  to handle an array which is declared as X(N,M)
  110. you have to declare X as a one-dimensional array and handle the indexing 
  111. yourself.
  112.  
  113. Thus a call to the NAG matrix inversion routine F01AAF with Fortran 
  114. declaration 
  115.  
  116.  SUBROUTINE F01AAF(A, IA, N, UNIT, IUNIT, WKSPCE, IFAIL)
  117.  INTEGER IA, N, IUNIT, IFAIL
  118.  REAL*8 A(IA,N), UNIT(IUNIT,N), WKSPCE(N)
  119.  
  120. would be simulated with dummy declarations something like
  121.  
  122.  procedure f01aaf(var a:realarray;       { realarray is declared in the 
  123.                                            FortLink unit }
  124.                   var ia, n:longint; 
  125.                   var unit:realarray;
  126.                   var iunit:longint;
  127.                   var wkspce:realarray;
  128.                   var ifail:longint);
  129.  
  130. and element A(I,J) would be addressed at a[i+(j-1)*ia].
  131.  
  132. The content of the dummy pascal routine is very simple, and should not be 
  133. varied.  If the Fortran routine is a SUBROUTINE, use a definition like
  134.   
  135.   const 
  136.     f01aaf_num = 1;  { this is the position of F01AAF in the call to CALLTP }
  137.  
  138.   procedure f01aaf;
  139.   begin
  140.     callfort(f01aaf_num);
  141.   end;
  142.  
  143. If desired, additional instructions can be put before the call to callfort;
  144. however, no local variables may be declared and no instructions may follow the 
  145. call.
  146.    
  147. If the Fortran routine is a FUNCTION, what to do depends on the function's 
  148. type.  Fortran and TP agree on the convention for returning values up to 4 
  149. bytes (except singles/REAL*4), so callfort can be used for these functions.
  150. The most common would be a Fortran INTEGER function being declared as a TP 
  151. longint function and using callfort.
  152.  
  153. However, Fortran and TP use different conventions for other return types, and 
  154. you need to use special calls to do the conversion. If the Fortran routine is 
  155. a REAL*8-valued FUNCTION, the "fdouble" procedure replaces callfort.  Use 
  156. "fsingle" for REAL*4 values.  For example, for the Gaussian random number 
  157. generator G05DDF, the Fortran declaration is 
  158.  
  159.  REAL*8 FUNCTION G05DDF(A, B)
  160.  REAL*8 A, B
  161.  
  162. and the Pascal declarations are
  163.  
  164.  function g05ddf(var a,b:double):double;
  165.  
  166. with implementation
  167.  
  168.  const g05ddf_num = 2;
  169.  function g05ddf;
  170.  begin
  171.    fdouble(g05ddf_num);   { Note that this is a procedure! }
  172.  end;
  173.  
  174. Other structured types can also be returned with some care.  You have to 
  175. declare the dummy function to be a pointer to the appropriate type, and use 
  176. the "fpointer(procnum)" call to the Fortran routine.  TPFORT only reserves 
  177. 8 bytes of space for return values, but larger values can be returned with 
  178. some trickery as described in FORTLINK.DOC in the header for fpointer.
  179.  
  180. 3.  Preparing the TP main program 
  181.  
  182. Once you have your dummy procedure unit set up, you have to make some 
  183. modifications to the main program to link in the Fortran at run-time.
  184. This is all done in a single call to 
  185.  
  186.  function loadfort(prog:string;TPentry:pointer):boolean;
  187.  
  188. The prog argument should contain a string giving the fully qualified name of 
  189. the Fortran program to be loaded; TPentry should give the address of a TP 
  190. routine taking no arguments, which is going to do all the calculations with 
  191. the Fortran routines.  It's necessary to do things this way because the call 
  192. to loadfort switches over to the Fortran stack; TPentry^ and any routine it 
  193. calls must be able to execute there.  If LoadFort is successful, it wo